package com.eric.enderslastgame;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.eric.enderslastgame.threads.BugGenThread;
import com.eric.enderslastgame.threads.GameThread;
import com.eric.enderslastgame.threads.LevelThread;
import com.eric.enderslastgame.threads.RenderThread;
import com.eric.enderslastgame.threads.SetSwitchThread;
import com.example.enderslastgame.R;

public class EndersGamePanel extends SurfaceView implements
		SurfaceHolder.Callback {

	// TODO Make each thread, loop their run methods and sleep(millis) at the
	// end
	// TODO more efficiency
	// TODO Gonna have to more all painting to Ender's Game

	private static final String TAG = EndersGamePanel.class.getSimpleName();

	public static final int SLEEP_TIME_REPAINT = 5, SLEEP_TIME_LEVEL = 10000,
			SLEEP_TIME_GAME_ACTIONS = 5;
	// TODO get: Fractions determining height given to each component
	public static final double BOARD_HEIGHT_FRACTION = 0.70, MINIMAP_HEIGHT_FRACTION = 0.30;

	public static int dodgedCounter = 0;
	public static int sets = 4; // Number of sets of Humans and Buggers going
								// on

	public static int panelWidth = 0, panelHeight = 0;

	public static boolean inGame = true; // True indicates the user has not won
											// or lost yet
	private static Board board;
	public static ArrayList<Minimap> minimaps = new ArrayList<Minimap>();

	private final String RESTART_GAME = "RESTART_GAME";

	public ArrayList<Human> humans;
	public ArrayList<ArrayList<Bugger>> buggers;

	private BugGenThread bugGenThread;
	private GameThread gameThread;
	private LevelThread levelThread;
	private RenderThread renderThread;
	private SetSwitchThread setSwitchThread;

	public int level; // Number that varies the difficulty of the game
	public int currentSetGen; // The current set of Buggers/Human where Buggers
								// are being generated
	private int genCounter; // The number of generated Buggers. Gets reset after
							// a certain amount of generated Buggers
	public int bugGenSleepTime, setSwitchSleepTime;

	public EndersGamePanel(Context context) {
		super(context);
		getHolder().addCallback(this);

		level = 1;
		currentSetGen = 0;
		genCounter = 0;

		bugGenSleepTime = genBugGenSleep(level);
		setSwitchSleepTime = genSetSwitchSleep(level);

		bugGenThread = new BugGenThread(getHolder(), this);
		gameThread = new GameThread(getHolder(), this);
		levelThread = new LevelThread(getHolder(), this);
//		renderThread = new RenderThread(getHolder(), this);
		setSwitchThread = new SetSwitchThread(getHolder(), this);
		
		Log.d(TAG, "Went through constructor");
	}

	private void startThreads() {
		bugGenThread.start();
		gameThread.start();
//		levelThread.start();
//		renderThread.start();
//		setSwitchThread.start();
		Log.d(TAG, "Started threads");
	}

	private void stopThreads() {
		inGame = false;
		Log.d(TAG, "Stopped threads (inGame = false)");
	}

	private void reInitialize() {
		inGame = true;

		// Initialize Humans and Buggers
		humans = new ArrayList<Human>();
		buggers = new ArrayList<ArrayList<Bugger>>();
		for (int i = 0; i < sets; i++) {
			humans.add(new Human(BitmapFactory.decodeResource(getResources(),
					R.drawable.human), BitmapFactory.decodeResource(getResources(), R.drawable.human_mini), panelWidth / 2, panelHeight / 2));
			buggers.add(new ArrayList<Bugger>());
			if (i == 0) {
				board.setHuman(humans.get(i));
				board.setBuggers(buggers.get(i));
				minimaps.get(i).setHuman(null);
				minimaps.get(i).setBuggers(null);
			} else if (i < (sets - 1)) {
				minimaps.get(i).setHuman(humans.get(i));
				minimaps.get(i).setBuggers(buggers.get(i));
			}
		}
		level = 1;
		dodgedCounter = 0;
		currentSetGen = 0;
		genCounter = 0;
		startThreads();
	}

	// Check collisions between Human and Buggers given
	public void checkCollisions(Human human, ArrayList<Bugger> buggers) {
		for (int i = 0; i < buggers.size(); i++) {
			Bugger bugger = buggers.get(i);
			if (human.getRect().intersect(bugger.getRect())) {
				// human.setVisible(false); // TEMP COMMENT
				// bugger.setVisible(false); // TEMP COMMENT
//				inGame = false;
//				stopThreads();
			}
		}
	}

	// Insert a bugger at the top of its screen at a random x position
	public void generateBugger(ArrayList<Bugger> buggers) {
		int velocity, upperLimit, lowerLimit = 1;

		// x coordinate of Bugger spawning point
		int xSpawn = (int) (Math.random() * (EndersGamePanel.panelWidth)); // TODO gotta (-) Bugger width

		if (level == 1) {
			velocity = 1;
		} else {
			if (level > 4) {
				upperLimit = 4;
				upperLimit = 2;
			} else {
				upperLimit = level;
				if (upperLimit < 3) {
					lowerLimit = 1;
				} else {
					lowerLimit = upperLimit - 2;
				}
			}
			velocity = genRandNum(lowerLimit, upperLimit);
		}

		buggers.add(new Bugger(BitmapFactory.decodeResource(getResources(),
				R.drawable.bugger), BitmapFactory.decodeResource(getResources(), R.drawable.bugger_mini), xSpawn, 0, velocity));
//		Log.d(TAG, "Generated bugger at x coordinate: " + xSpawn);
		
		// System.out.println("Generated bugger at x coordinate: " + xSpawn);
		// TEMP
	}

	// Switch the Human and Buggers inside the given Minimap with the Human and
	// Buggers inside the Board
	public static void switchInsides(Minimap minimap) {
		Human minimapHuman = minimap.getHuman();
		Human boardHuman = board.getHuman();
		Human holderHuman = boardHuman;
		ArrayList<Bugger> minimapBuggers = minimap.getBuggers();
		ArrayList<Bugger> boardBuggers = board.getBuggers();
		ArrayList<Bugger> holderBuggers = boardBuggers;

		if (minimapHuman != null && minimapBuggers != null) {
			board.setHuman(minimapHuman);
			minimap.setHuman(holderHuman);
			board.setBuggers(minimapBuggers);
			minimap.setBuggers(holderBuggers);
		}
		
		Log.d(TAG, "Went through switchInsides method");
	}

	// Move the Human and Buggers inside the given Minimap to the Board
	// Move the Human and Buggers inside the Board back to its respective
	// Minimap
	public static void moveInsides(Minimap minimap) {
		Human minimapHuman = minimap.getHuman();
		Human boardHuman = board.getHuman();
		ArrayList<Bugger> minimapBuggers = minimap.getBuggers();
		ArrayList<Bugger> boardBuggers = board.getBuggers();

		if (minimapHuman != null && minimapBuggers != null) {
			// Find the empty minimap and fill it in with what's on the Board
			// now
			for (int i = 0; i < (sets - 1); i++) {
				Minimap currentMap = minimaps.get(i);
				if (currentMap.getHuman() == null
						&& currentMap.getBuggers() == null) {
					currentMap.setHuman(boardHuman);
					currentMap.setBuggers(boardBuggers);
					board.setHuman(minimapHuman);
					board.setBuggers(minimapBuggers);
					minimap.setHuman(null);
					minimap.setBuggers(null);
				}
			}
		}
		
		Log.d(TAG, "Went through moveInsides method");
	}

	// Function for generating the delay for the set switch timer.
	// As x increases, the returned value decreases
	public int genSetSwitchSleep(int x) {
		int toReturn;

		int delay = (-500 * (level ^ 2) + 6000);

		if (delay > 0) {
			toReturn = delay;
		} else {
			toReturn = 1000;
		}

		return toReturn;
	}

	// Function for generating the delay for the set switch timer.
	// As x increases, the returned value decreases
	public int genBugGenSleep(int x) {
		int toReturn;
		int delay = (int) (-10 * (level ^ 2) + 600);

		if (delay > 0) {
			toReturn = delay;
		} else {
			toReturn = 200;
		}
		return toReturn;
	}

	public void render(Canvas canvas) {
		canvas.drawColor(Color.BLACK);
		board.draw(canvas);
		// minimap.draw(canvas);
//		Log.d(TAG, "Went through render method");
	}

	// Generate random number between the numbers specified (inclusive)
	private int genRandNum(int lower, int higher) {
		return (int) (Math.random() * (higher - lower + 1) + lower);
	}

	@Override
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Canvas canvas;

		canvas = null;

		try {
			canvas = getHolder().lockCanvas();
			panelWidth = canvas.getWidth();
			Log.d(TAG, "Surface View Width is " + panelWidth);
			panelHeight = canvas.getHeight();
			Log.d(TAG, "Surface View Height is " + panelHeight);
		} finally {
			// in case of an exception the surface is not left in
			// an inconsistent state
			if (canvas != null) {
				getHolder().unlockCanvasAndPost(canvas);
			}
		}

		// Initialize Humans and Buggers
		humans = new ArrayList<Human>();
		buggers = new ArrayList<ArrayList<Bugger>>();
		for (int i = 0; i < sets; i++) {
			humans.add(new Human(BitmapFactory.decodeResource(getResources(),
					R.drawable.human), BitmapFactory.decodeResource(getResources(), R.drawable.human_mini), panelWidth / 2, panelHeight / 2));
			buggers.add(new ArrayList<Bugger>());
		}

		board = new Board(humans.get(0), buggers.get(0)); // Initialize the
															// board

		// Initialize Minimaps and add them to the JFrame
		for (int i = 0; i < (sets - 1); i++) {
			Minimap minimap;
			if (i == 0) {
				minimap = new Minimap(null, null, i); // Make the first
														// minimap empty
			} else {
				minimap = new Minimap(humans.get(i), buggers.get(i), i);
			}
			minimaps.add(minimap);
		}

		Log.d(TAG, "Went through surfaceCreated");
		startThreads();
		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.d(TAG, "Surface is being destroyed");
	}
}
